// TSGDoc.cpp : implementation of the CTSGDoc class
//

#include "stdafx.h"
#include "TSG.h"

#include "TSGDoc.h"

#include "Log.h"
#include "mpegts.h"
#include "TreeNode.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

static int AFX_CDECL LOG(LOG_LEVEL level, const wchar_t* lpszFormat, ...)
{
	va_list args;
	int nCount;
	wchar_t szText[512] = {0};

	va_start(args, lpszFormat);
	nCount = vswprintf_s(szText, sizeof(szText)/2, lpszFormat, args);
	va_end(args);
	
	szText[nCount] = 0x0D;
	szText[nCount+1] = 0x0A;
	szText[nCount+2] = 0;
	CLog Log(_T("[APP]"), 6, level, szText, lstrlen(szText));

	CLogNode* pLogNode = new CLogNode(Log);
	ASSERT(pLogNode);
	if(pLogNode)
	{
		theLogFile.AddLogNode(pLogNode);
	}

	return 0;
}



// CTSGDoc

IMPLEMENT_DYNCREATE(CTSGDoc, CDocument)

BEGIN_MESSAGE_MAP(CTSGDoc, CDocument)

END_MESSAGE_MAP()


// CTSGDoc construction/destruction

CTSGDoc::CTSGDoc()
{
	// TODO: add one-time construction code here
	m_progress = 0;
	m_hRules = NULL;

	m_hRules = new CDVBRule;
}

CTSGDoc::~CTSGDoc()
{
	if(m_hRules)
	{
		delete m_hRules;
		m_hRules = NULL;
	}
}

BOOL CTSGDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}




// CTSGDoc serialization

void CTSGDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here	
		// TS 188/204
		BYTE ch;
		SHORT offset = 0;
		CFile* hFile = ar.GetFile();
		
		while(offset < 204)
		{
			hFile->Seek(offset, CFile::begin);
			hFile->Read(&ch, 1);

			if(ch == 0x47)
			{
				hFile->Seek(187, CFile::current);
				hFile->Read(&ch, 1);
				if (ch == 0x47)
				{
					m_config.SetType(TS_188);
					m_config.SetOffset(offset);
					break;
				}
				hFile->Seek(15, CFile::current);
				hFile->Read(&ch, 1);
				if (ch == 0x47)
				{
					m_config.SetType(TS_204);
					m_config.SetOffset(offset);
					break;
				}
			}
			offset++;
		}//end of while

		m_config.SaveConfig();
	}
}


// CTSGDoc diagnostics

#ifdef _DEBUG
void CTSGDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CTSGDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG




CTSGConfig* CTSGDoc::GetConfig(void)
{
	return &m_config;
}

BOOL CTSGDoc::AnalyzeStream(void)
{
	BOOL bRet = FALSE;
	CString FileName = GetPathName();
	CFileException fe;
	CFile* pFile = GetFile(FileName,CFile::modeRead|CFile::shareDenyWrite, &fe);
	m_progress = 0;

	if (pFile == NULL)
	{
		ReportSaveLoadException(FileName, &fe,
			FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
		return FALSE;
	}

	LOG(LOG_INFO, _T("Open the TS File(%s)"), FileName);
	CTreeNode* pNode = new CTreeNode(FileName);
	
	::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_UPDATETREE, (WPARAM)pNode, 0);

	LONGLONG FileLength = pFile->GetLength();
	LONGLONG Position = 0;

	ULONGLONG startTime = GetTickCount64();
	pFile->Seek(0, CFile::begin);

	MpegParserInit();

	while(Position < FileLength)
	{
		BYTE buf[204] = {0};
		static UINT nTSPCount = 0;
		pFile->Read(buf, m_config.GetType());
		Position = pFile->GetPosition();
		nTSPCount++;

		if(buf[0] != 0x47)
		{
			//AfxMessageBox(_T("Error detected in this TS File, at Position!")); 
			break;
		}

		CTSP* pNewTSP = new CTSP(m_config.GetType(), buf);
		if (!pNewTSP->IsValid())
		{
			delete pNewTSP;
			pNewTSP = NULL;
		}

		if(pNewTSP)
		{
			CPID* hpid = new CPID(pNewTSP->GetPID());
			if(m_TSStatistic.FindPID(hpid->GetPID())== NULL)
			{
				m_TSStatistic.InsertPID(hpid);
			}
			else
			{
				delete hpid;
			}

			AssemblingTSP(pNewTSP, &m_TSStatistic);

			delete pNewTSP;
		}

		m_progress = (UINT)((Position*100)/FileLength);
	}

	MpegParserTerm();

	ULONGLONG endTime = GetTickCount64();

	double elapsed = (endTime-startTime)/1000.0;

	m_TSStatistic.Dump();

	LOG(LOG_INFO, _T("Analyze the stream Done! Have used %.3f seconds"), elapsed);	

	ReleaseFile(pFile, FALSE);

	return TRUE;
}

BYTE* CTSGDoc::GetSectionBuffer(SHORT pid, BYTE table_id, USHORT parameter, BYTE version, BYTE section_number)
{
	BYTE* pBuffer = NULL;

	CPID* pPID = m_TSStatistic.FindPID(pid);
	if(pPID)
	{
		CMpegTable *pTable = pPID->FindTable(table_id);
		if(pTable)
		{
			CSection *pSection = pTable->FindSection(parameter, version, section_number);
			if (pSection)
			{
				pBuffer = pSection->m_szData;
			}
		}
	}

	return pBuffer;
}

UINT CTSGDoc::GetProgress(void)
{
	return m_progress;
}

UINT CTSGDoc::GetDVBTableCount(void)
{
	UINT nCount = 0;
	if(m_hRules)
	{
		nCount = m_hRules->GetTableCount();
	}
	return nCount;
}

char* CTSGDoc::GetDVBTableName(UINT nIndex)
{
	char* pName = NULL;

	if(m_hRules)
	{
		pName = m_hRules->GetTableName(nIndex);
	}

	return pName;
}

BOOL CTSGDoc::ParseDVBTable(UINT nIndex, BYTE* pData, char* pLine, BYTE& bPosition)
{
	BOOL bRet = FALSE;

	if(m_hRules)
	{
		bRet = m_hRules->ParseTable(nIndex, pData, pLine, bPosition);
	}

	return bRet;
}

BOOL CTSGDoc::AddNewTable(DWORD_PTR pTable)
{
	BOOL bRet = FALSE;

	if(m_hRules)
	{
		bRet = m_hRules->AddTable(pTable);
	}

	return bRet;
}

INT CTSGDoc::GetTableIndex(BYTE table_id)
{
	int nIndex = 0;

	if(m_hRules)
	{
		nIndex = m_hRules->GetTableIndex(table_id);
	}

	return nIndex;
}

BOOL CTSGDoc::RebuildXML(void)
{
	BOOL bRet = FALSE;

	if(m_hRules)
	{
		bRet = m_hRules->RebuildXML();
	}

	return bRet;
}